#include "iso14443.h"


uint8_t pcb = 0x0a;

int8_t pcd_hlta(void)
{
    uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    int8_t status = MI_EMPTY;
    rd522_buff_t  rd522_buff;

#if RD522_DEBUG
    printf("\r\n == [HLTA] == \r\n");
#endif
    write_reg(snd_byte_num_reg, 0x04);
    write_reg(snd_bit_num_reg, 0x00);

    rd522_buff.command = PCD_TRANSMIT;
    rd522_buff.length  = 4;
    rd522_buff.data[0] = PICC_HLTA;
    rd522_buff.data[1] = 0;
    status = rd522_get_crc(CRC_A, 2, rd522_buff.data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
    rd522_buff.data[2] = crc_lsb;
    rd522_buff.data[3] = crc_msb;

    status = rd522_data_transceive(&rd522_buff);
		
    return status;
}

int8_t pcd_request(uint8_t req_code, uint8_t *ptagtype)
{
    int8_t status = MI_EMPTY;
    rd522_buff_t  rd522_buff;

#if RD522_DEBUG
    printf("\r\n == [REQA/WUPA] == \r\n");
#endif
	
    write_reg(command_reg, PCD_M1STOP | BIT7);	//command寄存器最高位需置1
    write_reg(snd_byte_num_reg, 0x00);
    write_reg(snd_bit_num_reg, 0x07); 			// Tx last bytes = 7
	clear_bit_mask(txmode_reg, BIT7); 			//不使能发送crc
    clear_bit_mask(rxmode_reg, BIT7); 			//不使能接收crc
    clear_bit_mask(status2_reg, BIT3);			//清零MF crypto1认证成功标记

//	printf("rec_begin_bit_pos_reg:%02x\r\n",read_reg(rec_begin_bit_pos_reg));	
	
    rd522_buff.command = PCD_TRANSCEIVE;
    rd522_buff.length = 1;
    rd522_buff.data[0] = req_code;

    status = rd522_data_transceive(&rd522_buff);
//	printf("status = %d\r\n", status);
	
	*ptagtype = rd522_buff.data[0];
    *(ptagtype + 1) = rd522_buff.data[1];

    if(!status && rd522_buff.length != 0x02)
    {
        return MI_BYTECOUNTERR;
    }

    return status;
}

int8_t pcd_anticoll(uint8_t sel_code, uint8_t *uid)
{
    int8_t status = MI_EMPTY;
    uint8_t i = 0;
    uint8_t coll_byte_pos = 0;			//冲突出现的字节位置,从零开始计算
    uint8_t coll_bit_pos = 0;			//冲突出现的bit位置，从零开始计算
    uint8_t snr[5];						//发完93+20，有冲突，读完所有FIFO数据回来
	uint8_t temp;
    uint8_t bytes = 2,send_byte_num = 2;	//发送字节数，nvb高4位
    uint8_t send_bit_num = 0;				//发送的bit数，nvb低4位
    uint8_t rec_begin_bit_pos = 0;		//从哪位开始作为一字节


    rd522_buff_t rd522_buff;
	
	memset(snr, 0, sizeof(snr));
#if RD522_DEBUG
    printf("\r\n == [Anticoll] == \r\n");
#endif
    do
    {
        write_reg(rec_begin_bit_pos_reg, rec_begin_bit_pos);//配置开始接收位寄存器
        rd522_buff.command = PCD_TRANSCEIVE;
        rd522_buff.length = bytes;
        rd522_buff.data[0] = sel_code;//sel
        rd522_buff.data[1] = ((send_byte_num & 0x0F) << 4) | (send_bit_num & 0x0f);//NVB
        write_reg(snd_byte_num_reg, send_byte_num);
        write_reg(snd_bit_num_reg, send_bit_num);    

		for(i = 0; i <=(coll_byte_pos); i++)
		{
			rd522_buff.data[2 + i] = snr[i];//组装要发送的字节内容
		}
		status = rd522_data_transceive(&rd522_buff);

		temp = snr[coll_byte_pos];//保存冲突字节的有效位
		if(status == MI_COLL)
		{
#if RD522_DEBUG
			printf("coll\r\n");
#endif
			rd522_buff.data[1] |= temp;//整合

			coll_byte_pos = rd522_buff.data[0] >> 4;
			coll_bit_pos  = rd522_buff.data[0]  & 0x0f;
#if RD522_DEBUG
			printf("coll_bit_pos is:%02x\r\n", coll_bit_pos);
			printf("coll_byte_pos is:%02x\r\n", coll_byte_pos);
#endif

			if(coll_bit_pos == 7)
			{
				send_byte_num     = send_byte_num + coll_byte_pos + 1;
				send_bit_num      = 0;
				rec_begin_bit_pos = 0;
				bytes = send_byte_num;
			}
			else
			{
				send_byte_num  = send_byte_num + coll_byte_pos;
				send_bit_num   = coll_bit_pos + 1;
				rec_begin_bit_pos = coll_bit_pos + 1;
				bytes = (send_byte_num+1);
			}

			for(i = 0; (5 >= coll_byte_pos) && (i < coll_byte_pos); i++)
			{
				snr[i] = rd522_buff.data[i + 1];//获取冲突前的字节
			}
			snr[coll_byte_pos] = (rd522_buff.data[coll_byte_pos + 1] & ~(0xFF << coll_bit_pos)) + (1 << coll_bit_pos); //组合冲突位字节内容
		}
		else if(MI_OK == status)
		{
			for(i=0; i < rd522_buff.length && (i <= 4); i++)  //增加(i <= 4)防止snr[4-i]溢出
			{
				snr[4-i] = rd522_buff.data[rd522_buff.length-i-1];
			}
			snr[coll_byte_pos] |= temp;//组合之前接收到的有效比特
		}
	}while(MI_COLL == status);
	write_reg(rec_begin_bit_pos_reg, 0);
    if(status == MI_OK)
    {
        for(i = 0; i < 4; i++)
        {
            uid[i] = snr[i];
        }
//		write_reg(rec_begin_bit_pos_reg, 0);   //配置开始接收位寄存器,恢复默认接收起始位置
        return MI_OK;
    }
    else
    {
        return MI_COLLERR;
    }
}

int8_t pcd_select(uint8_t select_code, uint8_t *psnr, uint8_t *psak)
{
    uint8_t i;
    int8_t status = MI_EMPTY;
    uint8_t snr_check;
    uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    rd522_buff_t  rd522_buff;
	
    snr_check = 0;
#if RD522_DEBUG
    printf("\r\n == [SELECT] == \r\n");
#endif
    write_reg(snd_byte_num_reg, 0x09);
    write_reg(snd_bit_num_reg, 0x00);

    rd522_buff.command = PCD_TRANSCEIVE;
    rd522_buff.length = 9;
    rd522_buff.data[0] = select_code;
    rd522_buff.data[1] = 0x70;

    for(i = 0; i < 4; i++)
    {
        snr_check ^= *(psnr + i);
        rd522_buff.data[i + 2] = *(psnr + i);
    }

    rd522_buff.data[6] = snr_check;
    status = rd522_get_crc(CRC_A, 7, rd522_buff.data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
    rd522_buff.data[7] = crc_lsb;
    rd522_buff.data[8] = crc_msb;
    status = rd522_data_transceive(&rd522_buff);

    if(status == MI_OK)
    {
        if(rd522_buff.length == 0x03)//含crc两字节
        {
            *psak = rd522_buff.data[0];
        }
        else
        {
			return MI_BYTECOUNTERR;
        }
    }
	
    return status;
}

int8_t pcd_rats_a(uint8_t *ats)
{
    uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    int8_t status = MI_EMPTY;
    rd522_buff_t  rd522_buff;
	
#if RD522_DEBUG
    printf("\r\n == [RATS] == \r\n");
#endif

    write_reg(snd_byte_num_reg, 0x04);
    write_reg(snd_bit_num_reg, 0x00);
	
    rd522_buff.command = PCD_TRANSCEIVE;
    rd522_buff.length = 4;
    rd522_buff.data[0] = 0xE0;
    rd522_buff.data[1] = 0x51;//FSD：5；CID：1
    status = rd522_get_crc(CRC_A, 2,  rd522_buff.data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
    rd522_buff.data[2] = crc_lsb;
    rd522_buff.data[3] = crc_msb;

    status = rd522_data_transceive(&rd522_buff);


    if(MI_OK == status && ats != NULL)
    {	
		memcpy(ats, rd522_buff.data, rd522_buff.length);
    }

    return status;
}

int8_t pcd_set_pps(uint8_t rate)
{
    uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    int8_t status = MI_EMPTY;
    rd522_buff_t  rd522_buff;
#if RD522_DEBUG
    printf("\r\n == [PPS] == \r\n");
#endif
    write_reg(snd_byte_num_reg, 0x05);
    write_reg(snd_bit_num_reg, 0x00);
	
    rd522_buff.command = PCD_TRANSCEIVE;
    rd522_buff.length = 5;

    rd522_buff.data[0] = 0xD1; 					//start Byte
    rd522_buff.data[1] = 0x11;                	//pps0用来指定是否发送pps1,pps1作用是指出发送的通信速率

    switch(rate)
    {
        case RATE_106:
            rd522_buff.data[2] = 0x00;        	//DRI/DSI--00/00
            break;

        case RATE_212:
            rd522_buff.data[2] = 0x05;        	//DRI/DSI--01/01
            break;

        case RATE_424:
            rd522_buff.data[2] = 0x0A;        	//DRI/DSI--10/10
            break;

        case RATE_848:
            rd522_buff.data[2] = 0x0F;        	//DRI/DSI--11/11
            break;

        default:
            rd522_buff.data[2] = 0x00;
            break;
    }

    status = rd522_get_crc(CRC_A, 3, rd522_buff.data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
    rd522_buff.data[3] = crc_lsb;
    rd522_buff.data[4] = crc_msb;

    status = rd522_data_transceive(&rd522_buff);

    if(status == MI_OK)
    {
        if(rd522_buff.data[0] != 0xD1)
        {
            return MI_ERR_PPS;
        }
    }
    else
        return MI_ERR_PPS;
	
	return status;
}

int8_t pcd_deselect(void)
{
    uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    int8_t status = MI_EMPTY;
    rd522_buff_t  rd522_buff;
	
#if RD522_DEBUG
    printf("\r\n == [DESELECT] == \r\n");
#endif
    write_reg(snd_byte_num_reg, 0x04);
    write_reg(snd_bit_num_reg, 0x00);

    rd522_buff.command = PCD_TRANSCEIVE;
    rd522_buff.length  = 4;
    rd522_buff.data[0] = 0xca;
    rd522_buff.data[1] = 0x01;
    status = rd522_get_crc(CRC_A, 2, rd522_buff.data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
    rd522_buff.data[2] = crc_lsb;
    rd522_buff.data[3] = crc_msb;

    status = rd522_data_transceive(&rd522_buff);
	
    return status;
}

int8_t pcd_get_card_uid(uint8_t *cln, uint8_t *uid, uint8_t *sak_tmp)
{
    uint8_t uid_tmp[4];
    uint8_t sak;
    int8_t tmp = MI_EMPTY;
    uint8_t atqa[2];
	
	*cln = 0;
	pcb = 0x0a;
	
//	write_reg(txcontrol_reg, 0x00);
//	delay_ms(50);
//	write_reg(txcontrol_reg, 0x1b);
//	delay_ms(50);
	
    tmp = pcd_request(0x52,atqa);
	
    if((tmp == MI_OK) || (tmp == MI_COLL))
    {
        tmp = pcd_anticoll(PICC_ANTICOLL1, uid_tmp);
        if(tmp == MI_OK)
        {
            tmp = pcd_select(PICC_ANTICOLL1, uid_tmp, &sak);
            
            if(tmp == MI_OK)
            {
                *sak_tmp = sak;

                if(sak & 0x04)//通过sak字节bit3来判断接收的UID字节是否完整
                {
					uid[0] = uid_tmp[1];
					uid[1] = uid_tmp[2];
					uid[2] = uid_tmp[3];
                    tmp = pcd_anticoll(PICC_ANTICOLL2, uid_tmp);//CLN2

                    if(tmp == MI_OK)
                    {
                        tmp = pcd_select(PICC_ANTICOLL2, uid_tmp, &sak);

                        if(tmp == MI_OK)
                        {
							*sak_tmp = sak;
							
                            if(sak & 0x04)
                            {
								uid[3] = uid_tmp[1];
								uid[4] = uid_tmp[2];
								uid[5] = uid_tmp[3];
                                tmp = pcd_anticoll(PICC_ANTICOLL3, uid_tmp);//CLN3

                                if(tmp == MI_OK)
                                {
                                    tmp = pcd_select(PICC_ANTICOLL3, uid_tmp, &sak);

                                    if(tmp == MI_OK)
                                    {
										*sak_tmp = sak;
										
                                        if(sak & 0x04)
                                        {
                                            return PROTOCOL_ERR;
                                        }
                                        else
                                        {
                                            *cln = 3;//级联为3，即10字节长UID
                                            uid[6] = uid_tmp[0];
                                            uid[7] = uid_tmp[1];
                                            uid[8] = uid_tmp[2];
                                            uid[9] = uid_tmp[3];

                                            return MI_OK;
                                        }
                                    }
                                    else
                                    {
                                        return MI_COLLERR;
                                    }
                                }
                                else
                                {
                                    return MI_COLLERR;
                                }
                            }
                            else
                            {
                                *cln = 2;//级联为2,7字节UID
                                uid[3] = uid_tmp[0];
                                uid[4] = uid_tmp[1];
                                uid[5] = uid_tmp[2];
                                uid[6] = uid_tmp[3];

                                return MI_OK;
                            }
                        }
                        else
                        {
                            return MI_COLLERR;
                        }
                    }
                    else
                    {
                        return MI_COLLERR;
                    }
                }
                else
                {
                    *cln = 1;//级联为1,4字节UID
                    uid[0] = uid_tmp[0];
                    uid[1] = uid_tmp[1];
                    uid[2] = uid_tmp[2];
                    uid[3] = uid_tmp[3];

                    return MI_OK;
                }
            }
            else
            {
                return MI_COLLERR;
            }
        }
        else
        {
            return MI_COLLERR;
        }
    }
    else
    {
        return MI_NOTAGERR;
    }
}

int8_t cpu_r_block(rd522_buff_t *rd522_buff)
{
	uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
    int8_t status = MI_EMPTY;

	rd522_buff->length = 4;

	rd522_buff->command = PCD_TRANSCEIVE;	//rd522收发命令
	write_reg(snd_byte_num_reg, rd522_buff->length);
	write_reg(snd_bit_num_reg, 0x00);
	rd522_buff->data[0] = pcb|0xa0;
	rd522_buff->data[1] = 0x01;//cid为1

	status = rd522_get_crc(CRC_A, rd522_buff->length-2, rd522_buff->data, &crc_lsb, &crc_msb);
	if(status != MI_OK) return status;
	rd522_buff->data[rd522_buff->length-2] = crc_lsb;
	rd522_buff->data[rd522_buff->length-1] = crc_msb;
	
	status = rd522_data_transceive(rd522_buff);//rd522发送命令

	return status;
}

//==============================================
//fmcos2.0命令收发函数,发送数据长度<128，接收<128
//发送和接收用一个缓存，要求发送大于64时，接收必须
//小于64
//==============================================
int8_t pcd_cmd_transceive(pcd_cmd_t *pcd_cmd)
{
	uint8_t crc_lsb = 0;
    uint8_t crc_msb = 0;
	uint8_t len_temp = pcd_cmd->length;//保存指令的长度，当要求发送大于64个字节时会链接分段分几次发送，而返回的长度会保存到这个变量所以需要先保存下来
	uint8_t tx_pos=0, rx_pos=0;//发送和接收相应的起始缓存位置
    int8_t status = MI_EMPTY;
	rd522_buff_t rd522_buff;//pcd_cmd->length是inf域的长度不超过60，rd522_buff.length是整个块的长度不超过64
	pcd_cmd->length = 0;
	do//如果链接需要连续发送
	{
		if(len_temp>60)
		{
			rd522_buff.length = 60+4;//指令60个字节+pcb cid crc
			len_temp -= 60;
			pcb |= 0x10;//链接
		}
		else
		{
			rd522_buff.length = len_temp+4;
			pcb &= ~0x10;//不链接
			tx_pos|=0x80;//用最高位来指示不链接退出循环
		}
		rd522_buff.command = PCD_TRANSCEIVE;	//rd522收发命令
		write_reg(snd_byte_num_reg, rd522_buff.length);
		write_reg(snd_bit_num_reg, 0x00);
		rd522_buff.data[0] = pcb;
		rd522_buff.data[1] = 0x01;//cid为1
		memcpy(&rd522_buff.data[2], &pcd_cmd->buff[(tx_pos&0x7f)*60], rd522_buff.length-4);//拷贝命令数据，数据长度大于60（不包含pcbcidcrc）就要链接，第一次从0开始，第二次从60开始
		status = rd522_get_crc(CRC_A, rd522_buff.length-2, rd522_buff.data, &crc_lsb, &crc_msb);
		if(status != MI_OK) return status;
		rd522_buff.data[rd522_buff.length-2] = crc_lsb;
		rd522_buff.data[rd522_buff.length-1] = crc_msb;
		
		status = rd522_data_transceive(&rd522_buff);//rd522发送命令
		
		while(1)//循环接收链接
		{
			if(status == MI_OK)
			{
				pcb ^= 0x01;//切换块号，pcb最低位为块号，初始时pcb应该为0x0a（不链接）
				pcd_cmd->length += rd522_buff.length-4;//返回的fmcos指令长度，需要减去pcb+cid+crc，如果返回的是r块，这里其实就是加0，r块没有inf域
				
				memcpy(&pcd_cmd->buff[rx_pos], &rd522_buff.data[2], rd522_buff.length-4);//拷贝fmcos返回的指令数据，最后两个字节为sw1和sw2
				
				if((rd522_buff.data[0] & 0x10) !=0)//第五位是链接位，置一表示链接
				{
					rx_pos = pcd_cmd->length;//保存接收的位置，下一次从这里继续接收
					cpu_r_block(&rd522_buff);//接收到链接需要返回r块
				}
				else
				{	
					tx_pos++;//发送链接，下一次从tx*60开始发送
					break;
				}
			}
			else return status;
		}
	}while((tx_pos&0x80) == 0);
	return status;
}

//==============================================
//fmcos2.0创建密钥文件并且添加密钥
//==============================================
int8_t pcd_creat_key(uint8_t *key)
{
	int8_t status = MI_EMPTY;
	pcd_cmd_t pc;
	
	pc.length = 12;
	pc.buff[0] = 0x80;
	pc.buff[1] = 0xe0;
	pc.buff[2] = 0x00;//密钥文件ID固定为0x0000
	pc.buff[3] = 0x00;
	pc.buff[4] = 0x07;
	pc.buff[5] = 0x3f;
	pc.buff[6] = 0x00;
	pc.buff[7] = 0x30;//一条8字节密钥需要0x0f的空间，至少需要创建能存放3条密钥的空间比较好
	pc.buff[8] = 0x01;
	pc.buff[9] = 0xf0;//增加密钥的权限
	pc.buff[10] = 0xff;
	pc.buff[11] = 0xff;
	
	status = pcd_cmd_transceive(&pc);
	
	if(status == MI_OK)
	{
		if(((uint16_t)pc.buff[0]<<8 | pc.buff[1]) == 0x9000)//添加密钥
		{
			pc.length = 18;
			pc.buff[0] = 0x80;
			pc.buff[1] = 0xd4;
			pc.buff[2] = 0x01;
			pc.buff[3] = 0x00;
			pc.buff[4] = 0x0d;
			pc.buff[5] = 0x39;
			pc.buff[6] = 0xf0;
			pc.buff[7] = 0xf5;
			pc.buff[8] = 0xaa;
			pc.buff[9] = 0x88;
			memcpy(&pc.buff[10], key, 8);
			
			status = pcd_cmd_transceive(&pc);
			if(status == MI_OK)
			{
				if(((uint16_t)pc.buff[0]<<8 | pc.buff[1]) == 0x9000)
				{
					return status;
				}
			}
		}
	}
	return MI_EMPTY;
}

//==============================================
//fmcos2.0创建目录，大小为200字节
//==============================================
int8_t pcd_creat_df(uint8_t *file_id)
{
	int8_t status = MI_EMPTY;
	pcd_cmd_t pc;
	
	pc.length = 19;
	pc.buff[0] = 0x80;
	pc.buff[1] = 0xe0;
	pc.buff[2] = *file_id;
	pc.buff[3] = *(file_id+1);
	pc.buff[4] = 0x0e;
	pc.buff[5] = 0x38;
	pc.buff[6] = 0x00;
	pc.buff[7] = 0xc8;
	pc.buff[8] = 0xf0;
	pc.buff[9] = 0xf5;
	pc.buff[10] = 0x95;
	pc.buff[11] = 0xff;
	pc.buff[12] = 0xff;
	pc.buff[13] = 0x76;
	pc.buff[14] = 0x77;
	pc.buff[15] = 0x78;
	pc.buff[16] = 0x66;
	pc.buff[17] = 0x54;
	pc.buff[18] = 0x54;
	
	status = pcd_cmd_transceive(&pc);
	
	if(status == MI_OK)
	{
		if(((uint16_t)pc.buff[0]<<8 | pc.buff[1]) == 0x9000)
		{
			return status;
		}
	}
	return MI_EMPTY;
}

//==============================================
//fmcos2.0创建二进制文件大小64字节
//==============================================
int8_t pcd_creat_bin(uint8_t *file_id)
{
	int8_t status = MI_EMPTY;
	pcd_cmd_t pc;
	
	pc.length = 12;
	pc.buff[0] = 0x80;
	pc.buff[1] = 0xe0;
	pc.buff[2] = *file_id;
	pc.buff[3] = *(file_id+1);
	pc.buff[4] = 0x07;
	pc.buff[5] = 0x28;
	pc.buff[6] = 0x00;
	pc.buff[7] = 0x64;
	pc.buff[8] = 0xf5;
	pc.buff[9] = 0xf5;
	pc.buff[10] = 0xff;
	pc.buff[11] = 0xff;
	
	status = pcd_cmd_transceive(&pc);
	
	if(status == MI_OK)
	{
		if(((uint16_t)pc.buff[0]<<8 | pc.buff[1]) == 0x9000)
		{
			return status;
		}
	}
	return MI_EMPTY;
}
